package com.me.bbs.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.me.bbs.anno.RequireAdmin;
import com.me.bbs.anno.RequireLogin;
import com.me.bbs.common.CommonConst;
import com.me.bbs.common.ImageCode;
import com.me.bbs.common.Resp;
import com.me.bbs.entity.Administrator;
import com.me.bbs.entity.Forum;
import com.me.bbs.entity.User;
import com.me.bbs.dto.UserDTO;
import com.me.bbs.service.IAdministratorService;
import com.me.bbs.service.IForumService;
import com.me.bbs.service.IUserService;
import com.me.bbs.vo.UserVO;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author lm
 * @since 2023-01-09
 */
@Api
@RestController
@Slf4j
@RequestMapping("/user")
public class UserController {
    @Resource
    private IUserService userService;
    @Resource
    private IAdministratorService administratorService;
    @Resource
    private IForumService forumService;
    @PostMapping("/login")
    public Resp<?> login(@RequestBody User user, HttpSession session,@RequestParam("code") String  code) {
        String sCode = (String) session.getAttribute("Code");
        if(!sCode.equals(code))
            return Resp.error("验证码输入错误");
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getUsername, user.getUsername());
        User queriedUser = userService.getOne(lambdaQueryWrapper);
        if (queriedUser == null) {
            return Resp.error("用户名不存在");
        }
        if (Objects.equals(queriedUser.getPassword(), user.getPassword())) {

            session.setAttribute("user", queriedUser.getUserId());
            UserDTO userDTO = new UserDTO();
            BeanUtils.copyProperties(queriedUser,userDTO);
            return Resp.success(userDTO, "成功");
        }
        return Resp.error("密码错误");
    }

    @PostMapping("/logout")
    @RequireLogin
    public Resp<?> logout(HttpSession session){
        session.invalidate();
        return Resp.success();
    }

    @PostMapping("/register")
    public Resp<?> register(@RequestParam("username") String username,
                            @RequestParam("password") String password,
                            @RequestParam("nickname") String nickname
            , @RequestParam("code") String  code, HttpSession session) {
        User user = new User();
        user.setUsername(username);
        user.setNickname(nickname);
        user.setPassword(password);
        String sCode = (String) session.getAttribute("Code");
        if(!sCode.equals(code))
            return Resp.error("验证码输入错误");
        //判空
        if (StringUtils.isEmpty(user.getUsername())
                || StringUtils.isEmpty(user.getNickname())
                || StringUtils.isEmpty(user.getPassword())
        ) {
            return new Resp<>(null, CommonConst.ERROR_CODE, "参数不能为空");
        }
        //判定是否符合格式
        if (!Pattern.matches(CommonConst.PASSWORD_REG, user.getPassword())
                || !Pattern.matches(CommonConst.USERNAME_REG, user.getUsername())
        )
            return new Resp<>(null, CommonConst.ERROR_CODE, "参数格式错误");
        //判定是否已存在
        boolean isUsernameExists = userService.lambdaQuery().eq(User::getUsername, username).exists();
        if(isUsernameExists)
            return new Resp<>(null, CommonConst.ERROR_CODE, "该用户名已存在，请重新输入");
        boolean isNicknameExists = userService.lambdaQuery().eq(User::getNickname, nickname).exists();
        if(isNicknameExists)
            return new Resp<>(null, CommonConst.ERROR_CODE, "该昵称已存在，请重新输入");

        userService.save(user);
        return new Resp<>(null, CommonConst.SUCCESS_CODE, null);
    }

    @PostMapping("/save")
    public Resp<?> save(@RequestBody UserVO userVO) {
        User user;

        try {
            if(userVO.getNickname() != null) {
                boolean isNicknameExists = userService.lambdaQuery()
                        .eq(User::getNickname, userVO.getNickname()).exists();
                if (isNicknameExists)
                    return new Resp<>(null, CommonConst.ERROR_CODE, "该昵称已存在，请重新输入");
            }
            user = new User();
            BeanUtils.copyProperties(userVO,user);
            LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(User::getUsername, user.getUsername());
            boolean isSuccess = userService.update(user, wrapper);
            if (!isSuccess)
                return Resp.error("更新失败");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return Resp.success("更新成功");
    }


    @PostMapping("/getUserInfo")
    public Resp<?> getUserInfo(HttpSession session) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        Object userIdObj = session.getAttribute("user");
        if(userIdObj == null) {
            return Resp.error(CommonConst.SESSION_TIME_OUT_CODE,"会话已过期，请重新登录");
        }

        User user = userService.getById((Long)userIdObj);
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(user,userDTO);
        return Resp.success(userDTO,"成功");
    }

    @PostMapping("/getUser")
    public Resp<?> getUser(@RequestParam String username) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, username);
        User originalUser = userService.getOne(wrapper);
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(originalUser,userDTO);
        return Resp.success(userDTO, "成功");
    }
    @GetMapping("/code")
    public void generatorCode(HttpServletResponse response,HttpSession session) {
        ImageCode imageCode = ImageCode.getInstance();
        //获取验证码内容
        String code = imageCode.getCode();
        //存放到Redis
        session.setAttribute("Code",code);
        //获取图片
        ByteArrayInputStream image = imageCode.getImage();
        //设置内容类型
        response.setContentType("image/jpg");
        byte[] bytes = new byte[1024];
        try (ServletOutputStream outputStream = response.getOutputStream()){
            while (image.read(bytes) != -1){
                outputStream.write(bytes);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @PostMapping("/{id}")
    public Resp<?> getUserById(@PathVariable Long id) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUserId, id);
        User originalUser = userService.getOne(wrapper);
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(originalUser,userDTO);
        return Resp.success(userDTO, "成功");
    }

    @PostMapping("/search")
    public Resp<?> searchUser(@RequestParam("current") Long current,
                              @RequestParam("size") Long size,
                              @RequestParam(value = "q") String q,
                              @RequestParam(value = "order",required = false) String order) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        SFunction<User,Object> orderColumn = User::getFansCount;
        if("postCount".equals(order))
            orderColumn = User::getPostCount;
        else if ("likeCount".equals(order)) {
            orderColumn = User::getLikeCount;
        }
        else if ("fansCount".equals(order))
            orderColumn = User::getFansCount;

        wrapper.like(User::getUsername, q).or().like(User::getNickname, q)
                        .orderByDesc(orderColumn);

        Page page = userService.getPage(new Page(current,size),wrapper );
        return Resp.success(page);
    }
}
